/*
 * udp_socket.cpp
 *
 *  Created on: 2008-11-27
 *      Author: fanliangliang
 */

#include "udp_socket.h"
#include "socket_exception.h"

BEGIN_NAMESPACE_TOXIC

UdpSocket::UdpSocket()
:Socket(UDP_SOCKET) {

}

UdpSocket::~UdpSocket() {

}

void UdpSocket::bind(const IpAddress& address, uint16_t port) {
	bind(SocketAddress(address, port));
}

void UdpSocket::bind(const SocketAddress& address) {
	if (::bind(descriptor(), address, SocketAddress::size()) != 0) {
		throw SocketException();
	}
}

void UdpSocket::bind(uint16_t port) {
	bind(SocketAddress(IpAddress::ANY, port));
}

size_t UdpSocket::sendTo(const void* buffer, size_t length, const IpAddress& address, uint16_t port) {
	return sendTo(buffer, length, SocketAddress(address, port));
}

size_t UdpSocket::sendTo(const void* buffer, size_t length, const SocketAddress& address) {
	const char* ptr = static_cast<const char*>(buffer);
	size_t nleft = length;

	while (nleft > 0) {
		size_t nsend = ::sendto(descriptor(), ptr, nleft, 0, address, SocketAddress::size());
		if (nsend == size_t(-1)) {
			throw SocketException();
		}
		nleft -= nsend;
		ptr += nsend;
	}
	return length;
}

size_t UdpSocket::receiveFrom(void* buffer, size_t length, IpAddress* address, uint16_t* port) {
	if (address == 0 && port == 0) {
		return receiveFrom(buffer, length, 0);
	}
	else {
		SocketAddress addr;
		size_t nrecv = receiveFrom(buffer, length, &addr);
		if (address != 0) {
			*address = addr.address();
		}
		if (port != 0) {
			*port = addr.port();
		}
		return nrecv;
	}
}

size_t UdpSocket::receiveFrom(void* buffer, size_t length, SocketAddress* address) {
	size_t nrecv = 0;
	if (address == 0) {
		nrecv = ::recvfrom(descriptor(), (char*)buffer, length, 0, 0, 0);
		if (nrecv == size_t(-1)) {
			throw SocketException();
		}
	}
	else {
		socklen_t socklen = SocketAddress::size();
		sockaddr_in addr;
		memset(&addr, 0, sizeof(sockaddr_in));
		nrecv = ::recvfrom(descriptor(), (char*)buffer, length, 0, reinterpret_cast<sockaddr*>(&addr), &socklen);
		if (nrecv == size_t(-1)) {
			throw SocketException();
		}
		*address = SocketAddress(addr);
	}

	return nrecv;
}

END_NAMESPACE_TOXIC
